package com.starsoft.frame.fileimport;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.starsoft.frame.fileimport.pojo.Column;
import com.starsoft.frame.fileimport.pojo.DataTable;
import com.starsoft.frame.fileimport.pojo.NullType;
import com.starsoft.frame.fileimport.pojo.Table;
import com.starsoft.frame.fileimport.pojo.ValueType;
import com.starsoft.frame.util.StringUtil;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;

public class JsonReader extends FileReaderImpl {
	private static Logger logger = LoggerFactory.getLogger(JsonReader.class);
	
	private String charset = "GBK";

	public JsonReader() {

	}
	
	@Override
	public DataTable read(String content, Table table) {
		return read(content, table, null);
	}

	public DataTable read(String content, Table table, String path) {
		DataTable dataTable = new DataTable();
		dataTable.setTable(table);
		List<Map<String, Object>> listValue = getMapList(content, path);
		if(listValue.isEmpty()){
			return dataTable;
		}
		readTitle(listValue.get(0), table);
		dataTable.setData(readData(listValue, table));
		return dataTable;
	}
	
	@Override
	public DataTable read(InputStream source, Table table) {
		DataTable dataTable = new DataTable();
		dataTable.setTable(table);
		List<Map<String, Object>> listValue = getMapList(source);
		if(listValue.isEmpty()){
			return null;
		}
		readTitle(listValue.get(0), table);
		dataTable.setData(readData(listValue, table));
		return dataTable;
	}
	
	public DataTable read(List<Map<String, Object>> listValue, Table table) {
		DataTable dataTable = new DataTable();
		dataTable.setTable(table);
		if(listValue.isEmpty()){
			return null;
		}
		readTitle(listValue.get(0), table);
		dataTable.setData(readData(listValue, table));
		return dataTable;
	}

	private List<Map<String, Object>> readData(List<Map<String, Object>> listValue, Table table) {
		List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();

		List<Column> columnList = table.getColumnList();
		for (int i = 0; i < listValue.size(); i++) {
			Map<String, Object> rowMap = new HashMap<String, Object>();
			Map<String, Object> rowData = listValue.get(i);
			for (Column column : columnList) {
				Object value = rowData.get(column.getCode());
				if (value != null && !column.getValueType().equals((getValueType(value)))) {
					value = str2Obj(value.toString(), column.getValueType(), column.getFormat());
				}
				if (value == null && column.getNullType() == NullType.nullable) {
					value = column.getDefaultValue();
				} else if (value == null && column.getNullType() != NullType.nullable) {
					throw new RuntimeException((i + table.getStartRow() + 1) + " row:"
							+ column.getName() + " can not be null");
				}
				rowMap.put(column.getMapKey(), value);
			}
			data.add(rowMap);
		}
		return data;
	}

	private void readTitle(Map<String, Object> mapObj, Table table) {
		Set<String> codeSet = mapObj.keySet();
		int colNum = codeSet.size();
		String[] names = new String[colNum];
		String[] codes = new String[colNum];
		ValueType[] types = new ValueType[colNum];
		NullType[] nullTypes = new NullType[colNum];
		Object[] defaults = new Object[colNum];

		int index=0;
		for (String value: codeSet) {
			codes[index] = value;
			types[index] = getValueType(mapObj.get(value));
			index++;
		}
			
		List<Column> columnList = table.getColumnList();
		if (columnList == null) {
			columnList = new ArrayList<Column>();
			for (int i = 0; i < colNum; i++) {
				Column column = new Column(null, codes[i], names[i], types[i], nullTypes[i],
						defaults[i]);
				columnList.add(column);
			}
			table.setColumnList(columnList);
		} else {
			for (int i = 0; i < colNum; i++) {
				Column column = table.getColumnByCode(codes[i]);
				if (column != null) {
					column.setColIndex(i);
					if (column.getValueType() == null) {
						column.setValueType(types[i]);
					}
				} else {
					logger.debug("{} not list in table", codes[i]);
				}
			}
			for (Column column : columnList) {
				if(column.getColIndex()==null){
				 	logger.warn("{} no value in input", column.getCode());
				}
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	private List<Map<String, Object>> getMapList(InputStream source) {
		List<Map<String, Object>> result = new ArrayList<Map<String,Object>>();
		ObjectMapper  objMapper = new ObjectMapper();
		try {
			result = objMapper.readValue(source, result.getClass());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	private List<Map<String, Object>> getMapList(String source, String path) {
		List<Map<String, Object>> result = new ArrayList<Map<String,Object>>();
		if(StringUtil.isEmpty(source)){
			return result;
		}
		if(path!=null) {
			JSON json = JSONUtil.parse(source);
			result = (List<Map<String, Object>>) JSONUtil.getByPath(json, path);
		} else {
			ObjectMapper  objMapper = new ObjectMapper();
			try {
				objMapper.readTree(source);
				result = objMapper.readValue(source, result.getClass());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return result;
	}
	
	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

}
